#include "Factory.h"

namespace etel{
	//Facotry
	SINGLETON_INIT(Factory);

	Regex* PRODUCE_REGEX(Factory::prdRegex){
		SINGLETON_GET(FactoryRegex, factoryRegex);

		return NULL;
	}

	//FactoryRegex
	SINGLETON_INIT(FactoryRegex);

	RString* PRODUCE_REGEX_A(FactoryRegex::prdRString){
		if (length <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 0;
			return NULL;
		}

		if (*start != STRING_DELI){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", STRING_DELI, *(start));
			excepLoc = 0;
			return NULL;
		}
		CodeType string = new CodeUnitType[length + 1];	//length-1==(length-2)+1	two quotes less at least
		CodeType p1 = string, p2 = NULL;
		for (CodeType p = start + 1; p < start + length && *p != L'\0'; p++){
			if (*p == ESCAPE_CHAR && p2 == NULL){
				if (p + 1 >= start + length){
					break;
				}
				switch (*(p + 1)){
				case L'f':
					*(p1++) = L'\f';
					break;
				case L'n':
					*(p1++) = L'\n';
					break;
				case L'r':
					*(p1++) = L'\r';
					break;
				case L'v':
					*(p1++) = L'\v';
					break;
				case L't':
					*(p1++) = L'\t';
					break;
				case ESCAPE_CHAR:
					*(p1++) = ESCAPE_CHAR;
					break;
				case STRING_DELI:
					*(p1++) = STRING_DELI;
					break;
				default:
					p2 = (p--) + 1;
				}
				p++;
			}
			else if (*p == ESCAPE_CHAR && p2 != NULL){
				EncodeType encode;
				swscanf_s(p2, L"%i", &encode);
				*(p1++) = encode;
				p2 = NULL;
			}
			else if (*p == L'\n'){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"attempting to wrap directly");
				excepLoc = p - start;
				delete [] string;
				return NULL;
			}
			else if (*p == *start){
				if (p == start + 1){
					swprintf_s(exception, INFO_SINGLE_SIZE, L"empty string");
					excepLoc = 1;
					delete [] string;
					return NULL;
				}
				if (p2 != NULL){
					swprintf_s(exception, INFO_SINGLE_SIZE, L"character escaping is not completed");
					excepLoc = p - start;
					delete [] string;
					return NULL;
				}
				resLength = (ExpSizeType) (p + 1 - start);
				swprintf_s(p1, 1, L"%s", L"");
				return new RString(string, true);
			}
			else if (p2 == NULL) *(p1++) = *p;
			else if (!IS_CODING(p, p2)){
				wcsncpy_s(string, length, p2, p + 1 - p2);
				swprintf_s(exception, INFO_SINGLE_SIZE, L"attempting to escape \"%c%s...\"", ESCAPE_CHAR, string);
				excepLoc = p - start;
				delete [] string;
				return NULL;
			}
		}
		swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
		excepLoc = length;
		delete [] string;
		return NULL;
	}

	RAnyChar* PRODUCE_REGEX_A(FactoryRegex::prdRAnyChar){
		if (length <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 0;
			return NULL;
		}

		if (*start != INF_CHAR){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", INF_CHAR, *(start));
			excepLoc = 0;
			return NULL;
		}
		resLength = 1;
		return new RAnyChar();
	}

	CodeUnitType PRODUCE_REGEX_A(FactoryRegex::prdChar){
		CodeType startCur = start;
		ExpSizeType lengthRem = length;

		if (lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 0;
			return NULL;
		}

		if (*(startCur) != STRING_DELI){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", STRING_DELI, *(startCur));
			excepLoc = 0;
			return NULL;
		}

		if (--lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 1;
			return NULL;
		}
		startCur++;

		CodeUnitType chr;
		CodeType startEscape;
		switch (*startCur){
		case STRING_DELI:
			swprintf_s(exception, INFO_SINGLE_SIZE, L"detecting unexpected \"%c\"", STRING_DELI);
			excepLoc = 1;
			return NULL;
		case ESCAPE_CHAR:
			if (--lengthRem <= 0){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
				excepLoc = 2;
				return NULL;
			}
			startEscape = ++startCur;
			switch (*startCur){
			case L'n':
				chr = L'\n';
				break;
			case L'f':
				chr = L'\f';
				break;
			case L't':
				chr = L'\t';
				break;
			case L'v':
				chr = L'\v';
				break;
			case L'r':
				chr = L'\r';
				break;
			case ESCAPE_CHAR:
				chr = ESCAPE_CHAR;
				break;
			case STRING_DELI:
				chr = STRING_DELI;
				break;
			default:
				while (true){
					if (!IS_CODING(startCur, startEscape)){
						InfoSingleType excepSub;
						wcsncpy_s(excepSub, startEscape, startCur + 1 - startEscape);
						swprintf_s(exception, INFO_SINGLE_SIZE, L"attempting to escape \"%c%s...\"", ESCAPE_CHAR, excepSub);
						excepLoc = startCur - start;
						return NULL;
					}

					if (--lengthRem <= 0){
						swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
						excepLoc = startCur + 1 - start;
						return NULL;
					}

					if (*(++startCur) == ESCAPE_CHAR){
						EncodeType encode;
						swscanf_s(startEscape, L"%i", &encode);
						chr = encode;
						break;
					}
				}
			}
			break;
		case L'\n':
			swprintf_s(exception, INFO_SINGLE_SIZE, L"attempting to wrap directly");
			excepLoc = 1;
			return NULL;
		default:
			chr = *startCur;
		}

		if (--lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = startCur + 1 - start;
			return NULL;
		}
		if (*(++startCur) != STRING_DELI){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", STRING_DELI, *startCur);
			excepLoc = startCur - start;
			return NULL;
		}
		resLength = startCur + 1 - start;
		return chr;
	}

	RCharRange* PRODUCE_REGEX_A(FactoryRegex::prdRCharRange){
		CodeType startCur = start;
		ExpSizeType lengthRem = length;

		if (lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 0;
			return NULL;
		}

		if (*(startCur) != RANGE_L){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", RANGE_L, *(startCur));
			excepLoc = 0;
			return NULL;
		}

		if (--lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = 1;
			return NULL;
		}

		CodeUnitType leftChar = NULL;
		ExpSizeType lengthSub;
		InfoSingleType exceptionSub;
		if (*(++startCur) != RANGE_I){
			leftChar = prdChar(startCur, lengthRem, lengthSub, exceptionSub, excepLoc);
			if (leftChar == NULL){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"left character extracting fails: %s", exceptionSub);
				excepLoc += startCur - start;
				return NULL;
			}

			if ((lengthRem -= lengthSub) <= 0){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
				excepLoc = length;
				return NULL;
			}
			if (*(startCur += lengthSub) != RANGE_I){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", RANGE_I, *(startCur));
				excepLoc = startCur - start;
				return NULL;
			}
		}

		if (--lengthRem <= 0){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
			excepLoc = length;
			return NULL;
		}

		CodeUnitType rightChar = NULL;
		if (*(++startCur) != RANGE_R){
			rightChar = prdChar(startCur, lengthRem, lengthSub, exceptionSub, excepLoc);
			if (rightChar == NULL){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"right character extracting fails: %s", exceptionSub);
				excepLoc += startCur - start;
				return NULL;
			}

			if ((lengthRem -= lengthSub) <= 0){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"extracting unfinished");
				excepLoc = length;
				return NULL;
			}
			if (*(startCur += lengthSub) != RANGE_R){
				swprintf_s(exception, INFO_SINGLE_SIZE, L"expecting \"%c\" but detecting \"%c\"", RANGE_R, *(startCur));
				excepLoc = startCur - start;
				return NULL;
			}
		}

		if (leftChar == NULL && rightChar == NULL){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"attempting to omit both left and right character");
			excepLoc = startCur - start;
			return NULL;
		}
		
		if (leftChar!=NULL && rightChar!=NULL && leftChar > rightChar) leftChar ^= rightChar ^= leftChar ^= rightChar;

		resLength = startCur + 1 - start;
		return new RCharRange(leftChar,rightChar);
	}

	RReference* PRODUCE_REGEX(FactoryRegex::prdRReference){
		if (length <= 0){
			swprintf_s(exception, INFO_SIZE, L"extracting unfinished");
			excepLoc = 0;
			return NULL;
		}

		if (!IS_NAME_HEAD(*start)){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"not begin with name head", RANGE_L);
			excepLoc = 0;
			return NULL;
		}

		if (*start == NON_SINGLE_HEAD &&(length <= 1 || !IS_NAME(*(start + 1)))){
			swprintf_s(exception, INFO_SINGLE_SIZE, L"Illegal single-character name \"%c\"", NON_SINGLE_HEAD);
			excepLoc = 1;
			return NULL;
		}

		CodeType startCur = start;
		while (length - 1 > 0 && IS_NAME(*(startCur + 1))){
			startCur++;
			length--;
		}

		CodeType regexName = new CodeUnitType[startCur + 2 - start];
		wcsncpy_s(regexName, startCur + 2 - start, start, startCur + 1 - start);
		resLength = startCur + 1 - start;
		return new RReference(regexName, true, basicSpace);
	}





	/*RUEncStream* Factory::cRUEncStream(CodeType start,ExpSizeType length,ExpSizeType& resLength,InfoType exception,InfoSizeType excepSize,CodeSizeType& excepLoc){
	CodeType p=start;
	if(*p!=ENC_STREAM_DELI){
	swprintf_s(exception,excepSize,L"not begin with \"%c\"",ENC_STREAM_DELI);
	excepLoc=0;
	return NULL;
	}
	EncodeType encode;
	EncStreamType* encStream=new EncStreamType;
	CodeType p1=NULL;
	for(p++;p<start+length && *p!=L'\0';p++){
	if(IS_BLANK_SL(*p) || *p==ENC_STREAM_DELI) {
	if(p1!=NULL){
	swscanf_s(p1,L"%i",&encode);
	encStream->push_back(encode);
	p1=NULL;
	}
	if(*p==ENC_STREAM_DELI){
	resLength=(ExpSizeType)(p-start+1);
	return new RUEncStream(encStream,true);
	}
	}else if(!IS_BLANK_SL(*p) && p1==NULL){
	p1=p;
	}
	}
	swprintf_s(exception,excepSize,L"no terminator found");
	excepLoc=length-1;
	delete encStream;
	return NULL;
	}*/
}